package com.lg.meng.observable.download;

import android.os.Environment;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;

/**
 * Created by xx on 2016/10/3.
 * Description: 断点下载工具
 */
public class FileDownloader {
    public static final String TAG = FileDownloader.class.getName();
    private static final String MSG_EXTERNAL_STORAGE_SPACE_NOT_ENOUGH = "外部存储存储空间不足，请清理后再重试！";
    private static final String MSG_EXTERNAL_STORAGE_UNAVAILABLE = "外部存储不可用！";
    private static final String MSG_UNKNOWN_HOST_EXCEPTION = "下载地址访问异常";
    private static final String MSG_MALFORMED_URL_EXCEPTION = "下载地址错误";
    private static final String MSG_IO_EXCEPTION = "下载出错:网络异常，请重试";
    private static final String FILE_NON_EXISTENT_EXCEPTION = "远程文件不存在";
    private static final String MSG_OTHER_EXCEPTION = "下载出错：其它错误";
    private boolean isDownloading; //是否正在下载
    private boolean intercept; //被用户取消下载

    public boolean isDownloading() {
        return isDownloading;
    }

    public void setIntercept(boolean intercept) {
        this.intercept = intercept;
        isDownloading = !intercept;
    }

    private DownloadObserver observer;


    /**
     * 创建文件保存的目录
     */
    private void createDownloadDir(String filePath) {
        File file = new File(filePath);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
    }

    private String downloadType;

    public FileDownloader(String downloadType) {
        this.downloadType = downloadType;
    }

    /**
     * 下载入口
     *
     * @param fileUrl
     * @param filePath
     * @param observer
     */
    public void download(String fileUrl, String filePath, DownloadObserver observer) {
        Log.d("FileDownloader", "fileUrl:" + fileUrl);
        this.observer = observer;
        //判断外部存储是否可用
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            if (observer != null) {
                observer.onDownloadFailed(downloadType, this, MSG_EXTERNAL_STORAGE_UNAVAILABLE);
            }
            return;
        }
        DownloadThread thread = new DownloadThread(fileUrl, filePath);
        thread.start();
    }

    private int precent = 0; //正在发送固件的发送进度
    float speed; //下载速度 byte/秒
    int remainTime; //剩余下载时间：秒
    int downloadCount;
    int contentLength;

    /**
     * 同步获取下载信息
     */
    public void syncDownloadInfo() {
        if (isDownloading) {
            if (observer != null) {
                observer.onDownloadStart(downloadType, FileDownloader.this, contentLength);
                observer.onDownloadSpeed(downloadType, FileDownloader.this, speed, remainTime);
                observer.onDownloading(downloadType, FileDownloader.this, downloadCount, contentLength, precent);
            }
        }
    }

    /**
     * 下载文件的线程，支持断点续传(利用缓存文件实现)
     */
    private class DownloadThread extends Thread {
        private String fileUrl;
        private String filePath;

        public DownloadThread(String fileUrl, String filePath) {
            this.filePath = filePath;
            this.fileUrl = fileUrl;
        }

        @Override
        public void run() {
            setIntercept(false);
            InputStream is = null;
            RandomAccessFile raf = null;
            try {
                createDownloadDir(filePath);
                URL url = new URL(fileUrl);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setReadTimeout(10 * 000);
                conn.setConnectTimeout(10 * 000);
                //判断是否存在缓存文件
                int startPos = 0;
                if (isTemFileExist(filePath)) {
                    startPos = (int) getTemFileSize(filePath);
                    //-1是防止文件已经下载好但是没有重命名而导致错误
                    if (startPos != 0) {
                        startPos -= 1;
                    }
                    conn.addRequestProperty("Range", "bytes=" + startPos + "-");
                }
                int responseCode = conn.getResponseCode();
                if (responseCode == 200 || responseCode == 206) {//如果设置了访问数据的范围，将返回206
                    int readDownloadSize = conn.getContentLength();
                    //判断外部存储空间是否够用
                    if (Environment.getExternalStorageDirectory().getUsableSpace() < readDownloadSize) {
                        if (observer != null) {
                            observer.onDownloadFailed(downloadType, FileDownloader.this, MSG_EXTERNAL_STORAGE_SPACE_NOT_ENOUGH);
                        }
                        return;
                    }
                    contentLength = readDownloadSize + startPos;
                    if (observer != null) {
                        observer.onDownloadStart(downloadType, FileDownloader.this, contentLength);
                    }
                    is = conn.getInputStream();
                    File temFile = getTemFile(filePath);
                    if (!temFile.exists()) {
                        temFile.createNewFile();
                    }
                    raf = new RandomAccessFile(temFile, "rw");
                    raf.seek(startPos);
                    byte[] buff = new byte[1024 * 40];
                    int len;
                    downloadCount = startPos;
                    long time = System.currentTimeMillis();
                    long passTime;
                    int temLen = 0; //计算速度时使用，单位字节
                    int prcentTem = 0;
                    if (observer != null) {
                        precent = (int) (((float) downloadCount / contentLength) * 100);
                        observer.onDownloading(downloadType, FileDownloader.this, downloadCount, contentLength, precent);
                    }
                    while ((len = is.read(buff)) != -1) {
                        if (intercept) {
                            if (observer != null) {
                                observer.onDownloadCancel(downloadType, FileDownloader.this);
                            }
                            return;
                        }
                        raf.write(buff, 0, len);
                        downloadCount += len;
                        temLen += len;

                        // 每下载完成2%就通知任务栏进行修改下载进度
                        precent = (int) (((float) downloadCount / contentLength) * 100);
                        if (observer != null) {
                            if (precent - prcentTem >= 2) {
                                observer.onDownloading(downloadType, FileDownloader.this, downloadCount, contentLength, precent);
                                prcentTem = precent;
                            }
                        }

                        //计算速度
                        passTime = System.currentTimeMillis() - time;
                        if (passTime > 1000) {
                            //时间大于2秒计算速度 单位：byte/s
                            speed = temLen / passTime * 1000;
                            //剩余下载时间：秒
                            remainTime = (int) ((contentLength - downloadCount) / speed);
                            temLen = 0;
                            time = System.currentTimeMillis();
                            if (observer != null) {
                                observer.onDownloadSpeed(downloadType, FileDownloader.this, speed, remainTime);
                            }
                        }
                    }
                    //缓存文件下载后之后
                    File file = new File(filePath);
                    temFile.renameTo(file);
                    if (observer != null) {
                        observer.onDownloadSuccess(downloadType, FileDownloader.this, file);
                    }
                    return;
                } else {
                    if (observer != null) {
                        observer.onDownloadFailed(downloadType, FileDownloader.this, FILE_NON_EXISTENT_EXCEPTION);
                    }
                }
            } catch (UnknownHostException e) {
                e.printStackTrace();
                if (observer != null) {
                    observer.onDownloadFailed(downloadType, FileDownloader.this, MSG_UNKNOWN_HOST_EXCEPTION);
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
                if (observer != null) {
                    observer.onDownloadFailed(downloadType, FileDownloader.this, MSG_MALFORMED_URL_EXCEPTION);
                }
            } catch (IOException e) {
                e.printStackTrace();
                if (observer != null) {
                    observer.onDownloadFailed(downloadType, FileDownloader.this, MSG_IO_EXCEPTION);
                }
            } catch (Exception e) {
                e.printStackTrace();
                if (observer != null) {
                    observer.onDownloadFailed(downloadType, FileDownloader.this, MSG_OTHER_EXCEPTION);
                }
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (raf != null) {
                    try {
                        raf.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                setIntercept(true);
            }
        }


    }

    /**
     * 判断缓存文件是否存在
     *
     * @param filePath
     * @return
     */
    private boolean isTemFileExist(String filePath) {
        File temFile = getTemFile(filePath);
        return temFile.exists();
    }


    /**
     * 获取缓存文件大小
     *
     * @param filePath
     * @return
     */
    public long getTemFileSize(String filePath) {
        File temFile = getTemFile(filePath);
        return temFile.length();
    }

    /**
     * 获取缓存文件
     *
     * @param filePath
     * @return
     */
    private File getTemFile(String filePath) {
        Log.e(TAG, "filePath:" + filePath);
        String temFilePath = filePath;
        if (filePath != null && filePath.contains(".")) {
            temFilePath = filePath.substring(0, filePath.lastIndexOf(".")) + ".sgh";
        }
        Log.e(TAG, "temFilePath:" + temFilePath);
        return new File(temFilePath);
    }
}
